package org.farng.mp3.filename;

import org.farng.mp3.AbstractMP3Tag;
import org.farng.mp3.MP3File;
import org.farng.mp3.TagException;
import org.farng.mp3.TagUtility;
import org.farng.mp3.id3.AbstractID3v2Frame;
import org.farng.mp3.id3.ID3v2_4;

import java.io.File;
import java.io.RandomAccessFile;

import java.util.Iterator;


/**
 * This class represents the filename. To create it, invoke
 * <code>FilenameTagBuilder.createFilenameTagFromMP3File</code> which returns
 * a complete parsed, evaluated, and matched FilenameTag.
 *
 * @author Eric Farng
 * @version $Revision: 1.16 $
 */
public class FilenameTag extends AbstractMP3Tag {
    /** parsed composite */
    private AbstractFilenameComposite composite = null;

    /** id3v2_4 tag created from composite */
    private ID3v2_4 id3tag = null;

    /** mp3file used to create this tag */
    private MP3File mp3file = null;

    /** DOCUMENT ME! */
    private String extension = null;

    public FilenameTag(FilenameTag copyObject) {
        super(copyObject);
        this.composite = (AbstractFilenameComposite) TagUtility.copyObject(copyObject.composite);
        this.id3tag    = new ID3v2_4(copyObject.id3tag);
        this.mp3file   = new MP3File(copyObject.mp3file);
        this.extension = new String(copyObject.extension);
    }

    /**
     * Creates a new FilenameTag object.
     */
    protected FilenameTag() {}

    /**
     * Sets the composite that this tag will use.
     *
     * @param composite the composite that this tag will use.
     */
    public void setComposite(AbstractFilenameComposite composite) {
        this.composite = composite;
    }

    /**
     * Returns the composite that this tag will use.
     *
     * @return the composite that this tag will use.
     */
    public AbstractFilenameComposite getComposite() {
        return composite;
    }

    /**
     * DOCUMENT ME!
     *
     * @param extension DOCUMENT ME!
     */
    public void setExtension(String extension) {
        this.extension = extension;
    }

    /**
     * DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     */
    public String getExtension() {
        return extension;
    }

    /**
     * Sets the frame of this tag
     *
     * @param frame the frame to set
     */
    public void setFrame(AbstractID3v2Frame frame) {
        if (frame != null) {
            if (id3tag == null) {
                id3tag = new ID3v2_4();
            }

            id3tag.setFrame(frame);

            if (composite != null) {
                composite.setFrame(frame);
            }
        }
    }

    /**
     * Returns a frame of this tag
     *
     * @param identifier ID3v2_4 ID of frame to get
     *
     * @return a frame of this tag
     */
    public AbstractID3v2Frame getFrame(String identifier) {
        if (id3tag != null) {
            return id3tag.getFrame(identifier);
        }

        return null;
    }

    /**
     * DOCUMENT ME!
     *
     * @param identifier DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     */
    public Iterator getFrameOfType(String identifier) {
        return id3tag.getFrameOfType(identifier);
    }

    /**
     * Sets the ID3v2_4 representation of this tag.
     *
     * @param id3tag the ID3v2_4 representation of this tag
     */
    public void setId3tag(ID3v2_4 id3tag) {
        this.id3tag = id3tag;

        if (id3tag != null) {
            Iterator iterator = id3tag.iterator();

            while (iterator.hasNext()) {
                composite.setFrame((AbstractID3v2Frame) iterator.next());
            }

            if (composite != null) {
                composite.matchAgainstTag(id3tag);
            }
        }
    }

    /**
     * Returns the ID3v2_4 representation of this tag
     *
     * @return the ID3v2_4 representation of this tag
     */
    public ID3v2_4 getId3tag() {
        return id3tag;
    }

    /**
     * DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     */
    public String getIdentifier() {
        return "FilenameTagv1.00";
    }

    /**
     * DOCUMENT ME!
     *
     * @param mp3file DOCUMENT ME!
     */
    public void setMp3file(MP3File mp3file) {
        this.mp3file = mp3file;
    }

    /**
     * DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     */
    public MP3File getMp3file() {
        return mp3file;
    }

    /**
     * DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     */
    public int getSize() {
        return composeFilename().length();
    }

    /**
     * DOCUMENT ME!
     *
     * @param tag DOCUMENT ME!
     *
     * @throws java.lang.UnsupportedOperationException DOCUMENT ME!
     */
    public void append(AbstractMP3Tag tag) {
        /**
         * @todo Implement this org.farng.mp3.AbstractMP3Tag abstract method
         */
        throw new java.lang.UnsupportedOperationException("Method append() not yet implemented.");
    }

    /**
     * DOCUMENT ME!
     *
     * @param file DOCUMENT ME!
     *
     * @throws org.farng.mp3.TagException DOCUMENT ME!
     * @throws java.io.IOException DOCUMENT ME!
     * @throws java.lang.UnsupportedOperationException DOCUMENT ME!
     */
    public void append(RandomAccessFile file)
                throws org.farng.mp3.TagException, java.io.IOException {
        /**
         * @todo Implement this org.farng.mp3.AbstractMP3Tag abstract method
         */
        throw new java.lang.UnsupportedOperationException("Method append() not yet implemented.");
    }

    /**
     * DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     */
    public String composeFilename() {
        if (composite != null) {
            return composite.composeFilename().trim() + "." + extension;
        }

        return null;
    }

    /**
     * DOCUMENT ME!
     *
     * @param file DOCUMENT ME!
     *
     * @throws java.io.IOException DOCUMENT ME!
     * @throws java.lang.UnsupportedOperationException DOCUMENT ME!
     */
    public void delete(RandomAccessFile file)
                throws java.io.IOException {
        /**
         * @todo Implement this org.farng.mp3.AbstractMP3Tag abstract method
         */
        throw new java.lang.UnsupportedOperationException("Method delete() not yet implemented.");
    }

    /**
     * DOCUMENT ME!
     *
     * @param identifier DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     */
    public boolean hasFrame(String identifier) {
        if (id3tag != null) {
            return id3tag.hasFrame(identifier);
        }

        return false;
    }

    public boolean hasFrameOfType(String identifier) {
        if (id3tag != null) {
            return id3tag.hasFrameOfType(identifier);
        }

        return false;
    }

    /**
     * DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     */
    public Iterator iterator() {
        if (composite != null) {
            return composite.iterator();
        } else {
            return null;
        }
    }

    /**
     * DOCUMENT ME!
     *
     * @param tag DOCUMENT ME!
     *
     * @throws java.lang.UnsupportedOperationException DOCUMENT ME!
     */
    public void overwrite(AbstractMP3Tag tag) {
        /**
         * @todo Implement this org.farng.mp3.AbstractMP3Tag abstract method
         */
        throw new java.lang.UnsupportedOperationException("Method overwrite() not yet implemented.");
    }

    /**
     * DOCUMENT ME!
     *
     * @param file DOCUMENT ME!
     *
     * @throws org.farng.mp3.TagException DOCUMENT ME!
     * @throws java.io.IOException DOCUMENT ME!
     */
    public void overwrite(RandomAccessFile file)
                   throws org.farng.mp3.TagException, java.io.IOException {
        write(file);
    }

    /**
     * DOCUMENT ME!
     *
     * @param file DOCUMENT ME!
     *
     * @throws java.io.IOException DOCUMENT ME!
     * @throws org.farng.mp3.TagException DOCUMENT ME!
     * @throws java.lang.UnsupportedOperationException DOCUMENT ME!
     */
    public void read(RandomAccessFile file)
              throws java.io.IOException, org.farng.mp3.TagException {
        /**
         * @todo Implement this org.farng.mp3.AbstractMP3FileItem abstract
         *       method
         */
        throw new java.lang.UnsupportedOperationException("Method read() not yet implemented.");
    }

    /**
     * DOCUMENT ME!
     *
     * @param file DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     *
     * @throws java.io.IOException DOCUMENT ME!
     * @throws java.lang.UnsupportedOperationException DOCUMENT ME!
     */
    public boolean seek(RandomAccessFile file)
                 throws java.io.IOException {
        /**
         * @todo Implement this org.farng.mp3.AbstractMP3Tag abstract method
         */
        throw new java.lang.UnsupportedOperationException("Method seek() not yet implemented.");
    }

    /**
     * DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     */
    public String toString() {
        String   string = "";
        Iterator iterator = iterator();

        while (iterator.hasNext()) {
            string += (iterator.next().toString() + "\n");
        }

        return string;
    }

    /**
     * DOCUMENT ME!
     *
     * @param tag DOCUMENT ME!
     *
     * @throws java.lang.UnsupportedOperationException DOCUMENT ME!
     */
    public void write(AbstractMP3Tag tag) {
        /**
         * @todo Implement this org.farng.mp3.AbstractMP3Tag abstract method
         */
        throw new java.lang.UnsupportedOperationException("Method write() not yet implemented.");
    }

    /**
     * DOCUMENT ME!
     *
     * @param file DOCUMENT ME!
     *
     * @throws java.io.IOException DOCUMENT ME!
     * @throws TagException DOCUMENT ME!
     */
    public void write(RandomAccessFile file)
               throws java.io.IOException, TagException {
        File originalFile = getMp3file().getMp3file();
        File newFile = new File(originalFile.getParentFile(), composeFilename());

        if (newFile.getName().equals(originalFile.getName()) == false) {
            file.getFD().sync();
            file.getChannel().close();
            file.close();
            file = null;

            // copy, then delete
            TagUtility.copyFile(originalFile, newFile);

            if (originalFile.delete() == false) {
                throw new TagException("Unable to delete original file: " + originalFile.getName());
            }

            ;

            // rename
            //if (originalFile.renameTo(newFile) == false) {
            //    throw new TagException("Unable to rename file: " + originalFile.getName() + " to " + newFile.getName());
            //}
        }
    }
}